﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using System.IO;

namespace Netfraction
{
	public static class ClientSettings
	{
		private static XDocument _xDoc = null;
		private static string _filePath;

		public static event EventHandler OnClientSettingsLoaded;

		public static void LoadSettings(string settingsPath, bool silentLoad = false)
		{
			if (!System.IO.File.Exists(settingsPath))
				CreateSettings(settingsPath);

			_filePath = settingsPath;
			_xDoc = XDocument.Load(settingsPath);

			Identity.PrivateId = TryGetXPathValue(ref _xDoc, @"//Settings/Identity/PrivateId");
			Identity.Name = TryGetXPathValue(ref _xDoc, @"//Settings/Identity/Name");
			Identity.Password = TryGetXPathValue(ref _xDoc, @"//Settings/Identity/Password");
			Identity.Email = TryGetXPathValue(ref _xDoc, @"//Settings/Identity/Email");
			Identity.Description = TryGetXPathValue(ref _xDoc, @"//Settings/Identity/Description");
			Identity.Connection = TryGetXPathValue(ref _xDoc, @"//Settings/Identity/ConnectionSpeed");

			Connection.HubAddress = TryGetXPathValue(ref _xDoc, @"//Settings/Connection/HubAddress");
			Connection.GatewayIP = TryGetXPathValue(ref _xDoc, @"//Settings/Connection/GatewayIP");

			Downloads.DownloadFolder = TryGetXPathValue(ref _xDoc, @"//Settings/Downloads/DownloadFolder");

			Appearance.Background.Colour = GetARGBColourFromXElement(TryGetXPathElement(ref _xDoc, @"//Settings/Appearance/Background/Colour"));
			Appearance.MessageText.Colour = GetARGBColourFromXElement(TryGetXPathElement(ref _xDoc, @"//Settings/Appearance/MessageText/Colour"));
			Appearance.MyText.Colour = GetARGBColourFromXElement(TryGetXPathElement(ref _xDoc, @"//Settings/Appearance/MyText/Colour"));
			Appearance.Nick.Colour = GetARGBColourFromXElement(TryGetXPathElement(ref _xDoc, @"//Settings/Appearance/Nick/Colour"));
			Appearance.MyNick.Colour = GetARGBColourFromXElement(TryGetXPathElement(ref _xDoc, @"//Settings/Appearance/MyNick/Colour"));
			Appearance.OperatorNick.Colour = GetARGBColourFromXElement(TryGetXPathElement(ref _xDoc, @"//Settings/Appearance/OperatorNick/Colour"));
			Appearance.UrlText.Colour = GetARGBColourFromXElement(TryGetXPathElement(ref _xDoc, @"//Settings/Appearance/UrlText/Colour"));
			Appearance.TimeStamp.Colour = GetARGBColourFromXElement(TryGetXPathElement(ref _xDoc, @"//Settings/Appearance/TimeStamp/Colour"));

			XElement timestampElem = TryGetXPathElement(ref _xDoc, @"//Settings/Appearance/TimeStamp");
			Appearance.TimeStamp.Enabled = bool.Parse(timestampElem.Attribute("Enabled").Value);
			Appearance.TimeStamp.Format = timestampElem.Element("Format").Value;

			Appearance.ChatStyle = (Appearance.ChatStyleEnum)Enum.Parse(typeof(Appearance.ChatStyleEnum), TryGetXPathValue(ref _xDoc, @"//Settings/Appearance/ChatStyle"));

			if (!silentLoad)
				ClientSettingsLoaded();
		}

		private static string TryGetXPathValue(ref XDocument xDoc, string path)
		{
			try
			{
				return xDoc.XPathSelectElement(path).Value;
			}
			catch (Exception e)
			{
				Console.WriteLine(e.Message);
			}

			return string.Empty;
		}

		private static XElement TryGetXPathElement(ref XDocument xDoc, string path)
		{
			try
			{
				return xDoc.XPathSelectElement(path);
			}
			catch (Exception e)
			{
				Console.WriteLine(e.Message);
			}

			return null;
		}

		private static void ClientSettingsLoaded()
		{
			if (OnClientSettingsLoaded != null)
				OnClientSettingsLoaded(null, new EventArgs());
		}

		private static Color GetARGBColourFromXElement(XElement colourElem)
		{
			if (colourElem == null)
				return Colors.Black;

			return Color.FromArgb(
				byte.Parse(colourElem.Attribute("a").Value),
				byte.Parse(colourElem.Attribute("r").Value),
				byte.Parse(colourElem.Attribute("g").Value),
				byte.Parse(colourElem.Attribute("b").Value));
		}

		public static void SaveSettings()
		{
			_xDoc.XPathSelectElement(@"//Settings/Identity/PrivateId").SetValue(Identity.PrivateId);
			_xDoc.XPathSelectElement(@"//Settings/Identity/Name").SetValue(Identity.Name);
			_xDoc.XPathSelectElement(@"//Settings/Identity/Password").SetValue(Identity.Password);
			_xDoc.XPathSelectElement(@"//Settings/Identity/Email").SetValue(Identity.Email);
			_xDoc.XPathSelectElement(@"//Settings/Identity/Description").SetValue(Identity.Description);
			_xDoc.XPathSelectElement(@"//Settings/Identity/ConnectionSpeed").SetValue(Identity.Connection);

			_xDoc.XPathSelectElement(@"//Settings/Connection/HubAddress").SetValue(Connection.HubAddress);
			_xDoc.XPathSelectElement(@"//Settings/Connection/GatewayIP").SetValue(Connection.GatewayIP);

			_xDoc.XPathSelectElement(@"//Settings/Downloads/DownloadFolder").SetValue(Downloads.DownloadFolder);

			SetARGBColourForXElement(ref _xDoc, @"//Settings/Appearance/Background/Colour", Appearance.Background.Colour);
			SetARGBColourForXElement(ref _xDoc, @"//Settings/Appearance/MessageText/Colour", Appearance.MessageText.Colour);
			SetARGBColourForXElement(ref _xDoc, @"//Settings/Appearance/MyText/Colour", Appearance.MyText.Colour);
			SetARGBColourForXElement(ref _xDoc, @"//Settings/Appearance/Nick/Colour", Appearance.Nick.Colour);
			SetARGBColourForXElement(ref _xDoc, @"//Settings/Appearance/MyNick/Colour", Appearance.MyNick.Colour);
			SetARGBColourForXElement(ref _xDoc, @"//Settings/Appearance/OperatorNick/Colour", Appearance.OperatorNick.Colour);
			SetARGBColourForXElement(ref _xDoc, @"//Settings/Appearance/UrlText/Colour", Appearance.UrlText.Colour);
			SetARGBColourForXElement(ref _xDoc, @"//Settings/Appearance/TimeStamp/Colour", Appearance.TimeStamp.Colour);

			_xDoc.XPathSelectElement(@"//Settings/Appearance/TimeStamp").SetAttributeValue("Enabled", Appearance.TimeStamp.Enabled.ToString());
			_xDoc.XPathSelectElement(@"//Settings/Appearance/TimeStamp").SetElementValue("Format", Appearance.TimeStamp.Format);
			
			_xDoc.XPathSelectElement(@"//Settings/Appearance/ChatStyle").SetValue(Appearance.ChatStyle.ToString());
			
			_xDoc.Save(_filePath);
		}

		public static void CreateSettings(string settingsPath)
		{
			if (!Directory.Exists(Path.GetDirectoryName(settingsPath)))
				Directory.CreateDirectory(Path.GetDirectoryName(settingsPath));

			XmlTextWriter xWriter = new XmlTextWriter(new FileStream(settingsPath, FileMode.Create, FileAccess.Write, FileShare.None), Encoding.UTF8);
			xWriter.Formatting = Formatting.Indented;

			xWriter.WriteStartDocument();
			xWriter.WriteStartElement("Settings");

			// Client Identity
			xWriter.WriteStartElement("Identity");
			xWriter.WriteElementString("PrivateId", string.Empty);
			xWriter.WriteElementString("Name", "NewUser");
			xWriter.WriteElementString("Password", string.Empty);
			xWriter.WriteElementString("Email", string.Empty);
			xWriter.WriteElementString("Description", string.Empty);
			xWriter.WriteElementString("ConnectionSpeed", "100");
			xWriter.WriteEndElement();

			xWriter.WriteStartElement("Connection");
			xWriter.WriteElementString("HubAddress", "adc://127.0.0.1:6356");
			xWriter.WriteElementString("GatewayIP", string.Empty);
			xWriter.WriteEndElement();

			xWriter.WriteStartElement("Downloads");
			xWriter.WriteElementString("DownloadFolder", string.Empty);
			xWriter.WriteEndElement();

			xWriter.WriteStartElement("Appearance");
			SetARGBColourForXWriter(ref xWriter, "Background", Color.FromArgb(255, 255, 255, 255));
			SetARGBColourForXWriter(ref xWriter, "MessageText", Color.FromArgb(255, 0, 0, 0));
			SetARGBColourForXWriter(ref xWriter, "MyText", Color.FromArgb(255, 0, 0, 128));
			SetARGBColourForXWriter(ref xWriter, "Nick", Color.FromArgb(255, 0, 100, 0));
			SetARGBColourForXWriter(ref xWriter, "MyNick", Color.FromArgb(255, 128, 0, 0));
			SetARGBColourForXWriter(ref xWriter, "OperatorNick", Color.FromArgb(255, 128, 0, 128));
			SetARGBColourForXWriter(ref xWriter, "UrlText", Color.FromArgb(255, 64, 64, 255));

			xWriter.WriteStartElement("TimeStamp");
			xWriter.WriteAttributeString("Enabled", "True");
			xWriter.WriteElementString("Format", "hh:mm:ss");
			SetARGBColourForXWriter(ref xWriter, Color.FromArgb(255, 255, 255, 255));
			xWriter.WriteEndElement();

			xWriter.WriteElementString("ChatStyle", "Inline");
			xWriter.WriteEndElement();

			xWriter.WriteEndElement();
			xWriter.WriteEndDocument();

			xWriter.Flush();
			xWriter.Close();

			LoadSettings(settingsPath, true);
		}

		private static void SetARGBColourForXWriter(ref XmlTextWriter xWriter, Color c)
		{
			xWriter.WriteStartElement("Colour");
			xWriter.WriteAttributeString("a", c.A.ToString());
			xWriter.WriteAttributeString("r", c.R.ToString());
			xWriter.WriteAttributeString("g", c.G.ToString());
			xWriter.WriteAttributeString("b", c.B.ToString());
			xWriter.WriteEndElement();
		}

		private static void SetARGBColourForXWriter(ref XmlTextWriter xWriter, string element, Color c)
		{
			xWriter.WriteStartElement(element);
			SetARGBColourForXWriter(ref xWriter, c);
			xWriter.WriteEndElement();
		}

		private static void SetARGBColourForXElement(ref XDocument xDoc, string p, Color c)
		{
			xDoc.XPathSelectElement(p).SetAttributeValue("a", c.A);
			xDoc.XPathSelectElement(p).SetAttributeValue("r", c.R);
			xDoc.XPathSelectElement(p).SetAttributeValue("g", c.G);
			xDoc.XPathSelectElement(p).SetAttributeValue("b", c.B);
		}

		public static class Connection
		{
			public static string HubAddress;
			public static string GatewayIP;
		}

		public static class Downloads
		{
			public static string DownloadFolder;
		}

		public static class Identity
		{
			public static string PrivateId;
			public static string Name;
			public static string Password;
			public static string Email;
			public static string Description;
			public static string Connection;
		}

		public static class Appearance
		{
			public enum ChatStyleEnum
			{
				Inline,
				NewLine
			}

			public static ChatStyleEnum ChatStyle;

			public struct Background
			{
				public static Color Colour;
			}

			public struct MessageText
			{
				public static Color Colour;
			}

			public struct MyText
			{
				public static Color Colour;
			}

			public struct Nick
			{
				public static Color Colour;
			}

			public struct MyNick
			{
				public static Color Colour;
			}

			public struct OperatorNick
			{
				public static Color Colour;
			}

			public struct UrlText
			{
				public static Color Colour;
			}

			public struct TimeStamp
			{
				public static Color Colour;
				public static bool Enabled;
				public static string Format;
			}
		}
	}
}
